package qf.index;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ZipUtil;
import cn.hutool.db.Db;
import cn.hutool.db.Entity;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;

import java.io.IOException;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

public class ReadAd {
    public static void main(String[] args) throws SQLException, IOException {

        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println(format.format(new Date()) + " 程序开始了~~~");
        String newDataName = "scholar_25_02.";
        String summaryTable = newDataName + "unified_search_summary_0120";
        String orderPmIdAdKwTable = newDataName + "order_pmid_ad_kw";
        String pmArticleTable = newDataName + "spider_pubmed_vip_extend";

        String limit = "";
//        String limit = " limit 1";
//        Map<Integer, byte[]> pmIdAndAdListMap = getPmIdAndAdListMap(pmArticleTable, "id", "pmid`,`author_extend",limit);
//        System.out.println("pmIdAndAdListMap.size(): " + pmIdAndAdListMap.size());
//        updateSummaryTable(summaryTable, "id", "pmid", pmIdAndAdListMap);
//        updateOrderPmIdAdKwTable(orderPmIdAdKwTable, "id", "pmid`,`ut_ad", pmIdAndAdListMap);


// main
    }

    public static void addPmAd(String summaryTable, String pmArticleTable, String limit) throws SQLException {
//        Map<Integer, byte[]> pmIdAndAdListMap = getPmIdAndAdListMap(pmArticleTable, "id", "pmid`,`author_extend",limit);
//        System.out.println("pmIdAndAdListMap.size(): " + pmIdAndAdListMap.size());
//        updateSummaryTable(summaryTable, "id", "pmid", pmIdAndAdListMap);
    }

//    public static void updateSummaryTable(String summaryTable, String autoId, String field, Map<Integer, byte[]> pmIdAndAdListMap) throws SQLException {
//        List<Entity> tableNum = Db.use().query("select count(1) as count from " + summaryTable);
//        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//        String limit = "";

    /// /        String limit = " limit 1";
//        int onePageNum = 10000;
//        if (tableNum.get(0).getInt("count") > 0) {
//            int tableMax = Db.use().queryNumber("select max(" + autoId + ") from " + summaryTable).intValue();
//            Collection<Integer> tableList = new ArrayList<>();
//            NumberUtil.appendRange(0, tableMax + onePageNum, onePageNum, tableList);
//            tableList.parallelStream().forEach(startId -> {
//                try {
//                    List<Entity> tableData = Db.use().query("select `" + autoId + "`,`" + field + "` from " + summaryTable + " where " + autoId + " between " + startId + " and " + (startId + onePageNum - 1) + limit);
//                    System.out.println("\033[31;1m" + format.format(new Date()) + " ⑾ 更新AD，现在开始：" + startId + " 表名：" + summaryTable + Utils.printMemoryStr() + "\033[0m");
//                    for (Entity entry : tableData) {
//                        Integer pmId = entry.getInt("pmid");
//                        Integer id = entry.getInt(autoId);
//                        if (null != pmId && pmIdAndAdListMap.containsKey(pmId) && null != id && id > 0) {
//                            byte[] bytes = pmIdAndAdListMap.get(pmId);
//                            String ads = ZipUtil.unGzip(bytes, "utf-8");
//                            try {
//                                Db.use().update(Entity.create().set("pm_ad", ads), Entity.create(summaryTable).set(autoId, id));
//                            } catch (SQLException e) {
//                                e.printStackTrace();
//                            }
//                        }
//                    }
//                } catch (SQLException e) {
//                    e.printStackTrace();
//                }
//            });
//        }
//    }
    public static void updateOrderPmIdAdKwTable(String orderPmIdAdKwTable, String autoId, String field, Map<Integer, byte[]> pmIdAndAdListMap) throws SQLException {
        List<Entity> tableNum = Db.use().query("select count(1) as count from " + orderPmIdAdKwTable);
        String limit = "";
//        String limit = " limit 1";
        int onePageNum = 1000;
        if (tableNum.get(0).getInt("count") > 0) {
            int tableMax = Db.use().queryNumber("select max(" + autoId + ") from " + orderPmIdAdKwTable).intValue();
            Collection<Integer> tableList = new ArrayList<>();
            NumberUtil.appendRange(0, tableMax + onePageNum, onePageNum, tableList);
            tableList.parallelStream().forEach(startId -> {
                try {
                    List<Entity> tableData = Db.use().query("select `" + autoId + "`,`" + field + "` from " + orderPmIdAdKwTable + " where " + autoId + " between " + startId + " and " + (startId + onePageNum - 1) + limit);
                    for (Entity entry : tableData) {
                        Integer pmId = entry.getInt("pmid");
                        Integer id = entry.getInt(autoId);
                        String utAd = entry.getStr("ut_c1");
                        if (null != pmId && pmIdAndAdListMap.containsKey(pmId) && null != id && id > 0 && null != utAd && utAd.length() > 8) {
                            byte[] bytes = pmIdAndAdListMap.get(pmId);
                            String ads = ZipUtil.unGzip(bytes, "utf-8");
                            List<String> adList = JSONObject.parseArray(ads, String.class);
                            utAd = utAd.toLowerCase().replace("people's republic of china", "china");
                            double max = 0.0;
                            String result = "";
                            for (String pmAd : adList) {
                                double score = calculateCosineSimilarity(getMap(utAd), getMap(pmAd.toLowerCase()));
                                if (score > max) {
                                    max = score;
                                    result = pmAd;
                                }
                            }
                            try {
                                Db.use().update(Entity.create().set("pm_ad", result).set("score", max), Entity.create(orderPmIdAdKwTable).set(autoId, id));
                            } catch (SQLException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            });
        }
    }

    public static Map<Integer, byte[]> getPmIdAndAdListMap(String pmArticleTable, String autoId, String field, String limit) throws SQLException {
        List<Entity> tableNum = Db.use().query("select count(1) as count from " + pmArticleTable);
//        String limit = "";
//        String limit = " limit 1";
        int onePageNum = 1000;
        Map<Integer, byte[]> pmIdAndAdListMap = new ConcurrentHashMap<>();
        if (tableNum.get(0).getInt("count") > 0) {
            int tableMax = Db.use().queryNumber("select max(" + autoId + ") from " + pmArticleTable).intValue();
            Collection<Integer> tableList = new ArrayList<>();
            NumberUtil.appendRange(0, tableMax + onePageNum, onePageNum, tableList);
            tableList.parallelStream().forEach(startId -> {
                try {
                    List<Entity> tableData = Db.use().query("select `" + autoId + "`,`" + field + "` from " + pmArticleTable + " where " + autoId + " between " + startId + " and " + (startId + onePageNum - 1) + limit);
                    for (Entity entry : tableData) {
                        Integer pmId = entry.getInt("pmid");
                        String authorExtend = entry.getStr("author_extend");
                        if (null != pmId && pmId > 0 && null != authorExtend && authorExtend.contains("Affiliation")) {
                            JSONArray objects = JSONUtil.parseArray(authorExtend);
                            List<String> adList = new ArrayList<>();
                            for (Object object : objects) {
                                JSON parse = JSONUtil.parse(object);
                                String affiliation = parse.getByPath("Affiliation").toString();
                                List<String> infoList = com.alibaba.fastjson.JSON.parseArray(affiliation, String.class);
                                for (String s : infoList) {
                                    if (!adList.contains(s) && s.length() > 8) {
                                        adList.add(s);
                                    }
                                }
                            }
                            if (!adList.isEmpty()) {
                                byte[] zip = ZipUtil.gzip(JSONUtil.toJsonStr(adList), "utf-8");
                                pmIdAndAdListMap.put(pmId, zip);
                            }
                        }
                    }
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            });
        }
        return pmIdAndAdListMap;
    }

    public static Map<String, Integer> getMap(String strings) {
        String[] split = strings.split(" ");
        Map<String, Integer> map = new HashMap<>();
        for (String s : split) {
            map.put(s, 1);
        }
        return map;
    }

    public static double calculateCosineSimilarity(Map<String, Integer> vectorA, Map<String, Integer> vectorB) {
        // 计算向量的内积
        double dotProduct = 0.0;
        for (Map.Entry<String, Integer> entry : vectorA.entrySet()) {
            String term = entry.getKey();
            int frequencyA = entry.getValue();
            if (vectorB.containsKey(term)) {
                int frequencyB = vectorB.get(term);
                dotProduct += frequencyA * frequencyB;
            }
        }

        // 计算向量的模长
        double normA = calculateVectorNorm(vectorA);
        double normB = calculateVectorNorm(vectorB);

        // 计算余弦相似度
        double cosineSimilarity;
        if (normA != 0 && normB != 0) {
            cosineSimilarity = dotProduct / (normA * normB);
        } else {
            cosineSimilarity = 0.0;
        }

        return cosineSimilarity;
    }

    public static double calculateVectorNorm(Map<String, Integer> vector) {
        double norm = 0.0;
        for (Map.Entry<String, Integer> entry : vector.entrySet()) {
            int frequency = entry.getValue();
            norm += Math.pow(frequency, 2);
        }
        norm = Math.sqrt(norm);
        return norm;
    }


}
